EasyPusher:开源RTSP直播推流Android UVC外接摄像头推送源码

您所在的位置:网站首页 Android camera类 外接摄像头 EasyPusher:开源RTSP直播推流Android UVC外接摄像头推送源码

EasyPusher:开源RTSP直播推流Android UVC外接摄像头推送源码

2024-05-26 19:35| 来源: 网络整理| 查看: 265

方案背景

最近EasyPusher针对UVC摄像头做了适配,我们结合了UVCCamera与EasyPusher支持将UVC摄像头的视频推送到RTSP服务器上,在此特别感谢UVCCamera这个牛逼的项目!

本篇文章主要是介绍怎么操作UVC摄像头的。为此,我们实现了一个专门检测UVC摄像头的服务:UVCCameraService类。

检测UVC摄像头的服务:UVCCameraService类 监听 ```java mUSBMonitor = new USBMonitor(this, new USBMonitor.OnDeviceConnectListener() { @Override public void onAttach(final UsbDevice device) { Log.v(TAG, "onAttach:" + device); mUSBMonitor.requestPermission(device); } @Override public void onConnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock, final boolean createNew) { releaseCamera(); if (BuildConfig.DEBUG) Log.v(TAG, "onConnect:"); try { final UVCCamera camera = new MyUVCCamera(); camera.open(ctrlBlock); camera.setStatusCallback(new IStatusCallback() { // ... uvc 摄像头链接成功 Toast.makeText(UVCCameraService.this, "UVCCamera connected!", Toast.LENGTH_SHORT).show(); if (device != null) cameras.append(device.getDeviceId(), camera); }catch (Exception ex){ ex.printStackTrace(); } } @Override public void onDisconnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) { // ... uvc 摄像头断开链接 if (device != null) { UVCCamera camera = cameras.get(device.getDeviceId()); if (mUVCCamera == camera) { mUVCCamera = null; Toast.makeText(UVCCameraService.this, "UVCCamera disconnected!", Toast.LENGTH_SHORT).show(); liveData.postValue(null); } cameras.remove(device.getDeviceId()); }else { Toast.makeText(UVCCameraService.this, "UVCCamera disconnected!", Toast.LENGTH_SHORT).show(); mUVCCamera = null; liveData.postValue(null); } } @Override public void onCancel(UsbDevice usbDevice) { releaseCamera(); } @Override public void onDettach(final UsbDevice device) { Log.v(TAG, "onDettach:"); releaseCamera(); // AppContext.getInstance().bus.post(new UVCCameraDisconnect()); } }); ```

这个类主要实现UVC摄像头的监听、链接、销毁、反监听,当有UVC摄像头链接成功后,会创建一个mUVCCamera对象。然后在MediaStream里, 我们改造了switchCamera,当参数传2时表示要切换到UVCCamera(0,1分别表示切换到后置、前置摄像头)。

创建

在创建摄像头时,如果是要创建uvc摄像头,那直接从服务里面获取之前创建的mUVCCamera实例:

```java if (mCameraId == 2) { UVCCamera value = UVCCameraService.liveData.getValue(); if (value != null) { // uvc camera. uvcCamera = value; value.setPreviewSize(width, height,1, 30, UVCCamera.PIXEL_FORMAT_YUV420SP,1.0f); return; // value.startPreview(); }else{ Log.i(TAG, "NO UVCCamera"); uvcError = new Exception("no uvccamera connected!"); return; } // mCameraId = 0; } ``` 预览

在预览时,如果uvc摄像头已经创建了,那执行uvc摄像头的预览操作:

```java UVCCamera value = uvcCamera; if (value != null) { SurfaceTexture holder = mSurfaceHolderRef.get(); if (holder != null) { value.setPreviewTexture(holder); } try { value.setFrameCallback(uvcFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP/*UVCCamera.PIXEL_FORMAT_NV21*/); value.startPreview(); cameraPreviewResolution.postValue(new int[]{width, height}); }catch (Throwable e){ uvcError = e; } } ```

这里我们选的colorFormat为PIXEL_FORMAT_YUV420SP 相当于标准摄像头的NV21格式。

关闭预览

同理关闭时,调用的是uvc摄像头的关闭。

```java UVCCamera value = uvcCamera; if (value != null) { value.stopPreview(); } ``` 销毁

因为我们这里并没有实质性的创建,所以销毁时也将实例置为null就可以了。

```java UVCCamera value = uvcCamera; if (value != null) { // value.destroy(); uvcCamera = null; } ``` 上层如何调用

有了这些操作,我们看看上层怎么调用的。 需要在Manifest里面增加若干代码,具体详见UVCCamera工程说明,代码如下:

```xml ```

然后代码在UVCActivity里,这个类可以在library分支的myapplication工程里找到,即这里。

启动或者停止UVC摄像头推送:

```java public void onPush(View view) { // 异步获取到MediaStream对象. getMediaStream().subscribe(new Consumer() { @Override public void accept(final MediaStream mediaStream) throws Exception { // 判断当前的推送状态. MediaStream.PushingState state = mediaStream.getPushingState(); if (state != null && state.state > 0) { // 当前正在推送,那终止推送和预览 mediaStream.stopStream(); mediaStream.closeCameraPreview(); }else{ // switch 0表示后置,1表示前置,2表示UVC摄像头 // 异步开启UVC摄像头 RxHelper.single(mediaStream.switchCamera(2), null).subscribe(new Consumer() { @Override public void accept(Object o) throws Exception { // 开启成功,进行推送. // ... mediaStream.startStream("cloud.easydarwin.org", "554", id); } }, new Consumer() { @Override public void accept(final Throwable t) throws Exception { // ooop...开启失败,提示下... t.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(UVCActivity.this, "UVC摄像头启动失败.." + t.getMessage(), Toast.LENGTH_SHORT).show(); } }); } }); } } }); } ```

这样整个推送就完成了。如果一切顺利,应当能在VLC播放出来UVC摄像头的视频了~~

我们再看看如何录像,也非常简单…

```java public void onRecord(View view) { // 开始或结束录像. final TextView txt = (TextView) view; getMediaStream().subscribe(new Consumer() { @Override public void accept(MediaStream mediaStream) throws Exception { if (mediaStream.isRecording()){ // 如果正在录像,那停止. mediaStream.stopRecord(); txt.setText("录像"); }else { // 没在录像,开始录像... // 表示最大录像时长为30秒,30秒后如果没有停止,会生成一个新文件.依次类推... // 文件格式为test_uvc_0.mp4,test_uvc_1.mp4,test_uvc_2.mp4,test_uvc_3.mp4 String path = getExternalFilesDir(Environment.DIRECTORY_MOVIES) + "/test_uvc.mp4"; mediaStream.startRecord(path, 30000); final TextView pushingStateText = findViewById(R.id.pushing_state); pushingStateText.append("\n录像地址:" + path); txt.setText("停止"); } } }); } ```

UVC摄像头还支持后台推送,即不预览的情况下进行推送,同时再切换到前台继续预览只需要调用一个接口即可实现,如下:

```java @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) { ms.setSurfaceTexture(surfaceTexture); // 设置预览的surfaceTexture } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { ms.setSurfaceTexture(null); // 设置预览窗口为null,表示关闭预览功能 return true; } ```

如果要彻底退出uvc摄像头的预览、推送,,只需要同时退出服务即可。

```java public void onQuit(View view) { // 退出 finish(); // 终止服务... Intent intent = new Intent(this, MediaStream.class); stopService(intent); } ``` EasyPusher

EasyPusher推流是EasyDarwin开源流媒体团队开发的一款推送流媒体音/视频流给标准RTSP流媒体服务器(如EasyDarwin、Wowza)的流媒体推送库,全平台支持(包括Windows/Linux(32 & 64),ARM各平台,Android、iOS),通过EasyPusher我们就可以避免接触到稍显复杂的RTSP/RTP/RTCP推送流程,只需要调用EasyPusher的几个API接口,就能轻松、稳定地把流媒体音视频数据推送给RTSP流媒体服务器进行处理和转发,EasyPusher经过长时间的企业用户体验,稳定性非常高。

tsingsee tsingsee



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3